import math
from block import *
import time
class Game:
    _block = None
    def __init__(self, block, win = 11):
        self._block = block;
        self._win = win;

    def eval(self):
        return self._block.smoothness() * 0.1 + self._block.monotonicity() + math.log(self._block.emptyCount()) * 2.7 + self._block.maxValue()

    def search(self, depth, alpha, beta, positions, cutoffs):
        # print(depth)
        bestMove = -1
        if self._block.playerTurn:
            bestScore = alpha
            for direction in [Direction.UP, Direction.DOWN, Direction. LEFT, Direction. RIGHT]:
                newBlock = self._block.clone()
                newBlock.move(direction)
                if not (newBlock == self._block):
                    
                    positions += 1
                    if newBlock.isWin(self._win):
                        return {'move' : direction, 'score' : 10000, 'positions' : positions, 'cutoffs' : cutoffs}
                    newGame = Game(newBlock, self._win);
                    newBlock.playerTurn = False;
                    if depth == 0:
                        result = {'move' : direction, 'score' : newGame.eval()}
                    else:
                        result = newGame.search(depth - 1, bestScore, beta, positions, cutoffs);
                        if result['score'] > 9900:
                            result['score'] -= 1;
                        positions = result['positions'];
                        cutoffs = result['cutoffs'];

                    if result['score'] > bestScore:
                        bestScore = result['score'];
                        bestMove = direction;
                    if bestScore > beta:
                        cutoffs += 1;
                        return {'move' : bestMove, 'score' : beta, 'positions' : positions, 'cutoffs' : cutoffs}
        else:
            bestScore = beta;
            candidates = [];
            poss = self._block.availablePos();
            scores = {1 : {}, 2 : {}}
            for value in scores.keys():
                for pos in poss:
                    # pos = poss[posIndex]
                    # 设置相应位置为2或者4
                    self._block.setPos(pos[0], pos[1], value);
                    scores[value][pos] = - self._block.smoothness() + self._block.islands();
                    self._block.setPos(pos[0], pos[1], 0);

            # 选举出候选人
            maxScore = max(max(scores[1].values()), max(scores[2].values()))
            for value in scores.keys():
                for pos in scores[value].keys():
                    if scores[value][pos] == maxScore:
                        candidates.append({'position' : pos, 'value' : value})

            # print(candidates)
            # 遍历每一个候选人
            for candidate in candidates:
                position = candidate['position']
                value = candidate['value']
                newBlock = self._block.clone();
                newBlock.setPos(position[0], position[1], value);
                newBlock.playerTurn = True;
                positions += 1
                newGame = Game(newBlock);
                result = newGame.search(depth, alpha, bestScore, positions, cutoffs);
                positions = result['positions'];
                cutoffs = result['cutoffs'];

                if result['score'] < bestScore:
                    bestScore = result['score']
                if bestScore < alpha:
                    cutoffs += 1
                    return {'move':None, 'score':alpha, 'positions':positions, 'cutoffs':cutoffs}
        # print(bestScore)
        return {'move':bestMove, 'score':bestScore, 'positions':positions, 'cutoffs':cutoffs}

    def getBest(self):
        depth = 0
        best = None
        last = time.time()
        depth = 1;
        while time.time() - last < 0.5:
            # print(time.time() - last)
            newBest = self.search(depth, -10000, 10000, 0, 0);
            if newBest['move'] == -1:
                break;
            else:
                best = newBest;
            depth += 1
        print(depth)
        return best

def tranDirection(dire):
    res = {0:'up', 1:'down', 2:'left', 3:'right'}
    if(res.get(dire) == None):
        return 'up'
    return res[dire]

if __name__ == '__main__':
    b = Block([[1,0,0,0],[2,1,3,2],[6,7,5,2],[4,1,4,1]])
    g = Game(b)
    print(g.getBest())
    g._block.print()
    while not g._block.isWin(11):
        if g._block.isDead():
            break;
        move = g.getBest()
        newBlock = g._block;
        newBlock.move(move['move'])
        move['move'] = tranDirection(move['move'])
        print(move)
        
        newBlock.randomFill()
        g = Game(newBlock)
        # print('input the generate number please')
        # y,x,v = tuple(map(int, input().split(' ')))
        # g._block.setPos(y, x, v)
        g._block.print()
